package com.ywd.platform.netty.config;

import com.ywd.platform.netty.result.ServerStatus;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.concurrent.Future;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.stereotype.Component;

import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;

/**
 * Netty服务器启动器
 * 负责启动和停止Netty服务器
 */
@Slf4j
@Component
public class NettyServerLauncher implements ApplicationRunner, ApplicationListener<ContextClosedEvent> {

    private final ServerBootstrap serverBootstrap;
    private final InetSocketAddress tcpSocketAddress;
    private final EventLoopGroup bossGroup;
    private final EventLoopGroup workerGroup;

    private volatile Channel serverChannel;
    private volatile boolean isRunning = false;

    public NettyServerLauncher(ServerBootstrap serverBootstrap,
                               InetSocketAddress tcpSocketAddress,
                               EventLoopGroup bossGroup,
                               EventLoopGroup workerGroup) {
        this.serverBootstrap = serverBootstrap;
        this.tcpSocketAddress = tcpSocketAddress;
        this.bossGroup = bossGroup;
        this.workerGroup = workerGroup;
    }

    /**
     * 启动Netty服务器（非阻塞方式）
     */
    @Override
    public void run(ApplicationArguments args) {
        // 在新线程中启动服务器，避免阻塞Spring Boot主线程
        new Thread(this::startServer, "netty-server-starter").start();
    }

    /**
     * 启动Netty服务器（实际实现）
     */
    private void startServer() {
        try {
            log.info("开始启动Netty服务器, 地址: {}, 端口: {}",
                    tcpSocketAddress.getHostString(), tcpSocketAddress.getPort());
            // 绑定端口并启动服务器
            ChannelFuture bindFuture = serverBootstrap.bind(tcpSocketAddress);
            bindFuture.addListener(future -> {
                if (future.isSuccess()) {
                    serverChannel = bindFuture.channel();
                    isRunning = true;
                    log.info("Netty服务器启动成功, 地址: {}, 端口: {}",
                            tcpSocketAddress.getHostString(), tcpSocketAddress.getPort());
                    // 注册关闭钩子
                    registerShutdownHook();
                    // 添加关闭监听器（非阻塞）
                    serverChannel.closeFuture().addListener(closeFuture -> {
                        isRunning = false;
                        log.info("Netty服务器通道已关闭");
                    });
                } else {
                    log.error("Netty服务器启动失败", future.cause());
                    throw new RuntimeException("Netty服务器启动失败", future.cause());
                }
            });
            // 等待绑定完成（带超时）
            if (!bindFuture.awaitUninterruptibly(10, TimeUnit.SECONDS)) {
                log.error("Netty服务器启动超时");
                throw new RuntimeException("Netty服务器启动超时");
            }
        } catch (Exception e) {
            log.error("Netty服务器启动失败", e);
            throw new RuntimeException("Netty服务器启动失败", e);
        }
    }

    /**
     * 停止Netty服务器（Spring上下文关闭时调用）
     */
    @Override
    public void onApplicationEvent(ContextClosedEvent event) {
        shutdown();
    }

    /**
     * 优雅关闭服务器
     */
    public synchronized void shutdown() {
        if (!isRunning) {
            log.info("Netty服务器未运行，无需关闭");
            return;
        }
        log.info("开始关闭Netty服务器...");
        try {
            // 1. 关闭服务器通道
            if (serverChannel != null) {
                serverChannel.close().sync();
            }
            // 2. 关闭线程组（带超时）
            Future<?> bossShutdown = bossGroup.shutdownGracefully(0, 5, TimeUnit.SECONDS);
            Future<?> workerShutdown = workerGroup.shutdownGracefully(0, 5, TimeUnit.SECONDS);
            // 等待关闭完成
            bossShutdown.await(10, TimeUnit.SECONDS);
            workerShutdown.await(10, TimeUnit.SECONDS);

            isRunning = false;
            log.info("Netty服务器关闭完成");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.warn("Netty服务器关闭被中断");
        } catch (Exception e) {
            log.error("Netty服务器关闭失败", e);
        } finally {
            // 确保状态重置
            isRunning = false;
            serverChannel = null;
        }
    }

    /**
     * 注册JVM关闭钩子
     */
    private void registerShutdownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            log.info("JVM关闭检测，停止Netty服务器...");
            shutdown();
        }));
    }

    /**
     * 获取服务器状态信息
     */
    public ServerStatus getServerStatus() {
        return new ServerStatus(
                isRunning,
                tcpSocketAddress.getHostString(),
                tcpSocketAddress.getPort(),
                bossGroup instanceof NioEventLoopGroup ? ((NioEventLoopGroup) bossGroup).executorCount() : 0,
                workerGroup instanceof NioEventLoopGroup ? ((NioEventLoopGroup) workerGroup).executorCount() : 0
        );
    }

}
